class EappController < ApplicationController
  before_filter :login_required
  helper :sparklines
  def index
    if @eapp = Eapp.find(params[:id], :include => :eloads)
      @calculations = ["avg","std"]
      @columns = ["time","rendering_time","db_time"]
      @sort_column = "time"
      @sort_calculation = "avg"
      @sort_column = params[:sort_column] if params[:sort_column]
      @sort_calculation = params[:sort_calculation] if params[:sort_calculation]
      if eload = Eload.find(:first, :conditions => ["eapp_id=? and active=1",@eapp.id])
        erequests = Erequest.find(:all, :conditions => ["erequests.eapp_id=? and econtrollers.visible=1 and erequests.happened_at>eapps.start_on and erequests.happened_at<eapps.end_on and erequests.eload_id=?",@eapp.id,eload.id], :include => [:econtroller,:eapp], :group => "econtroller_id", :order => @sort_calculation+"(erequests."+@sort_column+") desc")
      else
        erequests = Erequest.find(:all, :conditions => ["erequests.eapp_id=? and econtrollers.visible=1 and erequests.happened_at>eapps.start_on and erequests.happened_at<eapps.end_on",@eapp.id], :include => [:econtroller,:eapp], :group => "econtroller_id", :order => @sort_calculation+"(erequests."+@sort_column+") desc")
      end
      @erequests = Array.new
      for erequest in erequests
        hash = Hash.new
        hash[:econtroller] = erequest
        hash[:econtroller]["count"] = Erequest.calculate("count", "id", :conditions => ["erequests.econtroller_id=?", erequest.econtroller.id], :include => :econtroller).to_i
        for calculation in @calculations 
          for column in @columns
            hash[:econtroller][column+"_"+calculation] = Erequest.calculate(calculation, column, :conditions => ["erequests.econtroller_id=?", erequest.econtroller.id], :include => :econtroller).to_f.round_to(5)
          end 
        end
        hash[:eactions] = Array.new
        for erequest in Erequest.find(:all, :conditions => ["erequests.eapp_id=? and erequests.econtroller_id=? and eactions.visible=1 and erequests.happened_at>eapps.start_on and erequests.happened_at<eapps.end_on",@eapp.id,erequest.econtroller.id], :include => [:eaction,:eapp], :group => "eaction_id", :order => @sort_calculation+"(erequests."+@sort_column+") desc")
          erequest["count"] = Erequest.calculate("count", "id", :conditions => ["erequests.eaction_id=?", erequest.eaction.id], :include => :eaction).to_i
          for calculation in @calculations 
            for column in @columns
              erequest[column+"_"+calculation] = Erequest.calculate(calculation, column, :conditions => ["erequests.eaction_id=?", erequest.eaction.id], :include => :eaction).to_f.round_to(5)
            end 
          end
          hash[:eactions] << erequest
        end
        @erequests << hash
      end
      @breadcrumbs = Array.new
      @breadcrumbs << {:title => @eapp.title, :url => {:action => :index, :id => @eapp.id}}
    else
      redirect_to :controller => :ehome, :action => :index
    end
  end
  def action
    if @eaction = Eaction.find(params[:id], :include => [:eapp])
      if eload = Eload.find(:first, :conditions => ["eapp_id=? and active=1",@eaction.eapp.id])
        @eaction = Eaction.find(:first, :include => [:erequests,:eapp], :conditions => ["eactions.id=? and erequests.happened_at>eapps.start_on and erequests.happened_at<eapps.end_on and erequests.eload_id=?",params[:id],eload.id])
      else
        @eaction = Eaction.find(params[:id], :include => [:erequests,:eapp], :conditions => ["erequests.happened_at>eapps.start_on and erequests.happened_at<eapps.end_on"])
      end
      @times = Array.new
      @db_times = Array.new
      @rendering_times = Array.new
      @times = @eaction.erequests.collect{|erequest| erequest.time} if @eaction
      @db_times = @eaction.erequests.collect{|erequest| erequest.db_time} if @eaction
      @rendering_times = @eaction.erequests.collect{|erequest| erequest.rendering_time} if @eaction
      @equeries = Equery.find(:all, :conditions => ["eactions.id=?",params[:id]], :include => [{:erequest=>[:eaction]}], :order => "equeries.time desc")
      @erequest_pages, @erequests = paginate(:erequests, :conditions => ["eactions.id=?",params[:id]], :include => [:eaction, :equeries], :order => "erequests.id desc, equeries.id asc", :per_page => 5)
      @eaction.visible=params[:visible] and @eaction.save if params[:visible]
      @eaction = Eaction.find(params[:id], :include => [:eapp])
      @breadcrumbs = Array.new
      @breadcrumbs << {:title => @eaction.eapp.title, :url => {:action => :index, :id => @eaction.eapp.id}}
      @breadcrumbs << {:title => @eaction.econtroller.title.titlecase+"#"+@eaction.title, :url => {:action => :action, :id => @eaction.id}}
    else
      redirect_to :controller => :ehome, :action => :index
    end
  end
  def load_new
    if eapp = Eapp.find(params[:id]) and params[:eload] and params[:eload][:title]
      Eload.new(:title => params[:eload][:title], :active => 0, :eapp_id => eapp.id).save
    end
    redirect_to :back
  end
  def load_update
    if eapp = Eapp.find(params[:id])
      Eload.update_all("active=0", ["eapp_id=?",eapp.id])
      if params[:eload][:id].to_i>0 and eload = Eload.find(params[:eload][:id], :conditions => ["eapp_id=?",eapp.id])
        eload.active = 1
        eload.save
      end
    end
    redirect_to :back
  end
  def run
    if eapp = Eapp.find(params[:id])
      traverse(eapp)
      analyze(eapp)
    end
    redirect_to :back
  end
  def analyze(eapp)
    eload_id = params[:eload][:id] if params[:eload] and params[:eload][:id]
    last_request = Erequest.find(:first, :conditions => ["eapp_id=?",eapp.id], :order => "id desc")
    log = File.open(eapp.directory+"/log/development.log","r").read
    log = log.scan(/Processing(.*?)(?=Processing|\Z)/m)
    for line in log
      line = line[0]
      entry = line.scan(/ (.*?)Controller\043(.*?) \(for (.*?) at (.*?)\) \[(.*?)\].*?Completed in (.*?) \(.*?\) . (?:(.*?): (.*?) \(.*?%\) . )?(?:(.*?): (.*?) \(.*?%\) . )?(.*?) (.*?) \[(.*?)\]/m)[0]
      if entry
        db,rendering = 0,0
        if entry[6]=="DB"
          db = entry[7]
        elsif entry[6]=="Rendering"
          rendering = entry[7]
        end
        if entry[8]=="DB"
          db = entry[9]
        elsif entry[8]=="Rendering"
          rendering = entry[9]
        end
        controller,action,ip,timestamp,protocol,time,code,status,url = entry[0],entry[1],entry[2],entry[3],entry[4],entry[5],entry[10],entry[11],entry[12]
        timestamp = timestamp.split(/[\:\- ]/)
        timestamp = Time.local(timestamp[0],timestamp[1],timestamp[2],timestamp[3],timestamp[4],timestamp[5])
        if last_request==nil or last_request.happened_at<timestamp
          econtroller = Econtroller.find_or_create_by_title_and_eapp_id(controller.downcase,eapp.id)
          eaction = Eaction.find_or_create_by_title_and_econtroller_id_and_eapp_id(action,econtroller.id,eapp.id)
          eviews = line.scan(/Rendering ([a-zA-Z]*?)\/(.*?)/)
          eview = nil
          if eviews[0]
            eview = Eview.find_or_create_by_title_and_econtroller_id_and_eapp_id(eviews[0][1],econtroller.id,eapp.id)
          end
          erequest = Erequest.new(:eapp_id => eapp.id, :happened_at => timestamp, :url => url, :time => time, :db_time => db.to_f, :rendering_time => rendering.to_f, :econtroller_id => econtroller.id, :eaction_id => eaction.id, :eview_id => (eview.id if eview))
          erequest.eload_id = eload_id if eload_id
          erequest.save
          qtypes = {0 => "SQL", 1 => "Load", 2 => "Columns", 3 => "Load Including Associations", 4 => "Update"}
          for qtype in qtypes
            queries = line.scan(/1m(.*?) ?#{qtype[1]} \((.*?)\).*[01]m(.*?).{4}$/)
            for query in queries
              model,time,sql = query[0],query[1],query[2]
              emodel = Emodel.find_or_create_by_title_and_eapp_id(model,eapp.id)
              Equery.new(:eapp_id => eapp.id, :erequest_id => erequest.id, :emodel_id => (emodel.id if emodel), :qtype => qtype[0], :query => sql.strip, :time => time.to_f).save
            end
          end
        end
      end
    end
  end
  def traverse(eapp)
    begin
      models = Dir.glob(eapp.directory+"/app/models/*.rb")
      models.map! {|file| File.basename(file,'.rb')}
      models.reject! {|file| file =~ /^_/}
      for model in models
        Emodel.find_or_create_by_title_and_eapp_id(model,eapp.id)        
      end
    rescue
    end
    controllers = Dir.glob(eapp.directory+"/app/controllers/*_controller.rb")
    controllers.each do |controller|
      begin
        controller_file = File.basename(controller, '.rb')
        controller_short = File.basename(controller, '_controller.rb')
        require eapp.directory+"/app/controllers/"+controller_file+".rb"
        controller_name = controller_file.camelize
        controller = controller_name.constantize
        econtroller = Econtroller.find_or_create_by_title_and_eapp_id(controller_short,eapp.id)
        methods = controller.instance_methods(false)
        for method in methods
          Eaction.find_or_create_by_title_and_econtroller_id_and_eapp_id(method,econtroller.id,eapp.id)
        end
        views = Dir.glob(eapp.directory+"/app/views/#{controller_short}/*.rhtml")
        views.map! {|file| File.basename(file,'.rhtml')}
        views.reject! {|file| file =~ /^_/}
        for view in views
          Eview.find_or_create_by_title_and_econtroller_id_and_eapp_id(view,econtroller.id,eapp.id)
        end
      rescue
      end
    end
  end
  def profile
    if @eapp = Eapp.find(params[:id])
      @address = params[:profile][:get]
      if !File.exist?(@eapp.directory+"/profile.rb")
        profile = File.open("#{RAILS_ROOT}/profile.rb","r").read.gsub(/ROOT/,@eapp.directory)
        File.open(@eapp.directory+"/profile.rb","w"){|f| f.write(profile)}
      end
      kernel_open("|ruby "+@eapp.directory+"/profile.rb "+@address)
    end
    lines = File.open(@eapp.directory+"/log/profile.log","r").read.split("\n")
    @lines = Array.new
    for line in lines[2..lines.length-1]
      @lines << line.split(/\s+/)
    end
  end
  def date_range
    if eapp = Eapp.find(params[:id])
      if !start_on = date_select_parse("eapp","start_on")
        start_on = Erequest.find(:first, :conditions => ["erequests.eapp_id=?",eapp.id], :order => "happened_at asc").happened_at || Date.today
      end
      if !end_on = date_select_parse("eapp","end_on")
        end_on = Erequest.find(:first, :conditions => ["erequests.eapp_id=?",eapp.id], :order => "happened_at desc").happened_at || Date.today
      end
      eapp.start_on = start_on
      eapp.end_on = end_on
      eapp.save
    end
    redirect_to :back
  end
end
